package com.niiwoo.civet.trade.service.local.loan.creditaduit;

import java.util.Date;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.dangdang.ddframe.rdb.sharding.api.HintManager;
import com.dangdang.ddframe.rdb.sharding.hint.HintManagerHolder;
import com.niiwoo.civet.trade.constant.LoanFlowMqConstant;
import com.niiwoo.civet.trade.dao.entity.Project;
import com.niiwoo.civet.trade.dao.entity.ProjectFlowExecute;
import com.niiwoo.civet.trade.dao.entity.ProjectFlowExecuteRuntime;
import com.niiwoo.civet.trade.dao.entity.TianChengRequestRecord;
import com.niiwoo.civet.trade.dao.mapper.ProjectFlowExecuteMapperExt;
import com.niiwoo.civet.trade.dao.mapper.ProjectFlowExecuteRuntimeMapperExt;
import com.niiwoo.civet.trade.dao.mapper.ProjectMapperExt;
import com.niiwoo.civet.trade.dao.mapper.TianChengRequestRecordMapperExt;
import com.niiwoo.civet.trade.dto.request.CreditAuditBackRequestDTO;
import com.niiwoo.civet.trade.dto.request.ProjectFlowRequestDTO;
import com.niiwoo.civet.trade.enums.FinalAuditResultEnum;
import com.niiwoo.civet.trade.enums.LoanNodeTypeEnum;
import com.niiwoo.civet.trade.enums.ProjectAuditResultEnum;
import com.niiwoo.civet.trade.enums.ProjectCreditTypeEnum;
import com.niiwoo.civet.trade.enums.ProjectFlowExecuteRuntimeNodeStatusEnum;
import com.niiwoo.civet.trade.enums.ProjectFlowExecuteStatusEnum;
import com.niiwoo.civet.trade.enums.ProjectStatusEnum;
import com.niiwoo.civet.trade.enums.ProjectSubStatusEnum;
import com.niiwoo.civet.trade.enums.ProjectTypeEnum;
import com.niiwoo.civet.trade.enums.TradeConfigEnum;
import com.niiwoo.civet.trade.service.local.common.ProjectCommonService;
import com.niiwoo.civet.trade.service.local.configure.TradeConfigLocalService;
import com.niiwoo.civet.trade.service.local.flowexecute.ProjectFlowExecuteService;
import com.niiwoo.civet.trade.service.local.loan.SpeedLoanService;
import com.niiwoo.civet.trade.service.local.loan.TianchengModelParseService;
import com.niiwoo.civet.trade.service.local.loan.antifraud.LoanAntiFraudLocalService;
import com.niiwoo.civet.trade.service.project.ProjectDubboService;
import com.niiwoo.civet.user.dto.request.AddUserLoanLimitRequestDTO;
import com.niiwoo.civet.user.dto.response.credit.CreditScoreCardDTO;
import com.niiwoo.civet.user.dto.response.credit.TianchengCreditBaseInfoResponseDTO;
import com.niiwoo.civet.user.enums.LibraLoanLimitEnum;
import com.niiwoo.civet.user.enums.ProductTypeEnum;
import com.niiwoo.civet.user.enums.SMSTemplateExtend.ProjectType;
import com.niiwoo.civet.user.enums.TianchengCallbackEventEnum;
import com.niiwoo.civet.user.service.TianchengDataDubboService;
import com.niiwoo.civet.user.service.UserForbidDubboService;
import com.niiwoo.tripod.service.component.SnowflakeIdWorker;
import com.niiwoo.tripod.tiancheng.enums.AgainstFakeErrorCodeEnum;
import com.niiwoo.tripod.tiancheng.enums.FunctionCodeEnum;
import com.niiwoo.tripod.tiancheng.request.afp.CreditAduitAgainLoanRequest;
import com.niiwoo.tripod.tiancheng.request.afp.CreditAduitFirstLoanRequest;
import com.niiwoo.tripod.tiancheng.request.afp.KaDaiRepairServiceRequest;
import com.niiwoo.tripod.tiancheng.response.common.AgainstFakeV2Response;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public abstract class AbstractCreditAuditService {
	
    @Value(value = "${web-http-url}")
    protected String webHttpUrl;
    
	@Autowired
	protected ProjectCommonService projectCommonService;
	
    @Autowired
    protected SpeedLoanService loanLocalService;
    
    @Autowired
    protected TradeConfigLocalService tradeConfigService;
    
    @Autowired
    protected ProjectDubboService projectDubboService;
    
    @Autowired
    protected LoanAntiFraudLocalService loanAntiFraudLocalService;
    
    @Autowired
    protected ProjectFlowExecuteService projectFlowExecuteService;
    
    @Autowired
    protected ProjectFlowExecuteMapperExt projectFlowExecuteMapperExt;
    
    @Autowired
    protected ProjectFlowExecuteRuntimeMapperExt projectFlowExecuteRuntimeMapperExt;
    
    @Autowired
    protected ProjectMapperExt projectMapper;
    
    @Autowired
    protected TianChengRequestRecordMapperExt tianChengRequestRecordMapperExt;
    
    @Autowired
    protected SnowflakeIdWorker snowflakeIdWorker;
    
    protected boolean isAgainLoan = true;
	
	public void creditAuditCallback(CreditAuditBackRequestDTO creditAuditBackRequestDTO) {
		log.info("天称{}信审回调,流程ID={},内部方法creditAuditCallback请求参数={}.", getProductName(), creditAuditBackRequestDTO.getFlowId(), JSON.toJSONString(creditAuditBackRequestDTO));
		Long flowExecuteId = creditAuditBackRequestDTO.getFlowId();
        
        //获取当前标的对应的流程的流程状态
    	ProjectFlowExecute flow = projectFlowExecuteMapperExt.selectByPrimaryKey(flowExecuteId);
    	if (flow == null) {
    		log.error("天称{}信审回调,流程ID={},流程不存在.", getProductName(), flowExecuteId);
            return;
    	}
    	if (flow.getStatus() != ProjectFlowExecuteStatusEnum.EXECUTING.getStatus()) { //不是执行中
    		log.error("天称{}信审回调,流程ID={},流程状态异常.", getProductName(), flowExecuteId);
            return;
    	}
    	
    	// shardingjdbc 强制走主库
		if (!HintManagerHolder.isMasterRouteOnly()) {
            HintManagerHolder.clear();
            HintManager hintManager = HintManager.getInstance();
            hintManager.setMasterRouteOnly();
        }
    	ProjectFlowExecuteRuntime projectFlowExecuteRuntime = projectFlowExecuteRuntimeMapperExt.selectByPrimaryKey(flowExecuteId);
    	if (projectFlowExecuteRuntime == null) {
            log.error("天称{}信审回调,流程ID={},ProjectFlowExecuteRuntime记录不存在", getProductName(), creditAuditBackRequestDTO.getProjectId());
            return;
        }
        if (LoanNodeTypeEnum.LOAN_SYSTEM_AUDIT_BACK.getId() != projectFlowExecuteRuntime.getNodeId().intValue()
        		&& LoanNodeTypeEnum.LOAN_SYSTEM_AUDIT.getId() != projectFlowExecuteRuntime.getNodeId().intValue()) {
            log.error("天称{}信审回调,标的ID={},节点ID={},节点不一致.", getProductName(), creditAuditBackRequestDTO.getProjectId(),projectFlowExecuteRuntime.getNodeId());
            return;
        }
        
        //用于流标请求
        FailCloseFlowEvent failCloseFlowEvent = new FailCloseFlowEvent();
        failCloseFlowEvent.setToClose(false);
        failCloseFlowEvent.setToFlow(false);
        
        ProjectFlowRequestDTO requestDTO = new ProjectFlowRequestDTO();
        requestDTO.setSubStatus(ProjectSubStatusEnum.MISCARRY_AUTO_FAILED);
        
        Project project = null;
		try {
			Integer auditResult = null;

			project = projectCommonService.queryProjectBasicInfo(creditAuditBackRequestDTO.getProjectId());
	        if (project == null) {
	            log.error("天称{}信审回调,标的ID={},发生异常,原因是标的不存在.", getProductName(), creditAuditBackRequestDTO.getProjectId());
	            // 清掉对应流程数据
	            projectFlowExecuteService.failEndProjectFlowExecute(flowExecuteId, LoanNodeTypeEnum.LOAN_SYSTEM_AUDIT_BACK, "标的不存在");
	            return;
	        }
	        
	        requestDTO.setProjectId(project.getProjectId());
	
	        if (!project.getStatus().equals(ProjectStatusEnum.CHECKING.getStatus())) {
	            log.error("天称{}信审回调,标的ID={},发生异常,原因是标的不在审核中状态.", getProductName(), creditAuditBackRequestDTO.getProjectId());
	            // 清掉对应流程数据
	            projectFlowExecuteService.failEndProjectFlowExecute(flowExecuteId, LoanNodeTypeEnum.LOAN_SYSTEM_AUDIT_BACK, "标的状态已变更");
	            return;
	        }
	
	        if (creditAuditBackRequestDTO.isRequestSuccess()) {
	            //1.审核通过;
	            if (creditAuditBackRequestDTO.isAuditPass()) {
	                log.info("天称{}信审回调,标的ID={},审核通过.", getProductName(), creditAuditBackRequestDTO.getProjectId());
	                auditResult = 1;
	                
	                loanLocalService.updateFinalAuditResult(project.getProjectId(),FinalAuditResultEnum.PASS);
	                
	                // 发送MQ肖像认证
	                projectFlowExecuteService.initNextStepProjectFlowExecute(flowExecuteId, LoanNodeTypeEnum.LOAN_SYSTEM_AUDIT_BACK, LoanNodeTypeEnum.PORTRAIT_AUTH, LoanFlowMqConstant.Queue.PORTRAIT_AUTH_QUEUE);
	            }
	
	            //2.审核拒绝
	            else if (creditAuditBackRequestDTO.isAuditReject()) {
	                log.info("天称{}信审回调,标的ID={},审核拒绝.", getProductName(), creditAuditBackRequestDTO.getProjectId());
	                auditResult = 2;
	
	                //2.2 通知用户借款审核不通过;
	                //2.3 限制用户借款行为
	                addUserLibraLoanLimit(project.getBorrowUserId());
	                
	                projectFlow(project.getProjectId(), flowExecuteId, LoanNodeTypeEnum.LOAN_SYSTEM_AUDIT_BACK, true, "天秤信审拒绝");
	            }
	            
	            //3.需要人工审核
	            else if (creditAuditBackRequestDTO.isAuditReview()) {
	                log.info("天称{}信审回调,标的ID={},需要人工审核.", getProductName(), creditAuditBackRequestDTO.getProjectId());
	                auditResult = 3;
					// 人工审核服务接口
	                loanLocalService.toManualAudit(project);
	                
	                // 发送人工审核之后直接结束流程
	                projectFlowExecuteService.successEndProjectFlowExecute(flowExecuteId, LoanNodeTypeEnum.MANPOWER_AUDIT);
	            }
	            
	            //1.2 更新标的自动审核结果;
	            loanLocalService.updateAutoAuditResult4Project(creditAuditBackRequestDTO.getProjectId(), auditResult.byteValue());
	            //1.1 记录自动审核结果， 新版本已经不存在AuditPoint信息
	            loanLocalService.addAutoAuditResult(creditAuditBackRequestDTO.getProjectId(), project.getBorrowUserId(), auditResult.byteValue(), creditAuditBackRequestDTO.getAuditPoints());
	        }
	        
	        //信审要点反欺诈请求失败;
	        else {
	            log.error("天称{}信审回调,标的ID={},发生异常,原因是信审要点请求失败.", getProductName(), creditAuditBackRequestDTO.getProjectId());
	            loanLocalService.updateAutoAuditResult4Project(creditAuditBackRequestDTO.getProjectId(), ProjectAuditResultEnum.TC_PARAM_ERROR.getCode());
	        
	            // 终止流程（异常）
	            failCloseFlowEvent.setToFlow(true);
	            failCloseFlowEvent.setErrorMsg("天秤信审请求失败");
	        }
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			
			failCloseFlowEvent.setToFlow(true);
            failCloseFlowEvent.setErrorMsg(e.getMessage());
		} finally  {
			if (project == null) return;
			
			if (failCloseFlowEvent.getToFlow())
				projectFlow(project.getProjectId(), flowExecuteId, LoanNodeTypeEnum.LOAN_SYSTEM_AUDIT_BACK, false, failCloseFlowEvent.getErrorMsg());
		}
    }
	
	public void addUserLibraLoanLimit(String userId) {
		AddUserLoanLimitRequestDTO addUserLoanLimitRequestDTO = new AddUserLoanLimitRequestDTO();
        addUserLoanLimitRequestDTO.setLimitDays(Integer.valueOf(tradeConfigService.selectTradeConfigByEmun(TradeConfigEnum.SYSTEMAUTOREJECTLIMITDAYS)));
        addUserLoanLimitRequestDTO.setLimitType(LibraLoanLimitEnum.LOAN_AUDIT.getLimitType().intValue());
        addUserLoanLimitRequestDTO.setUserId(userId);
        
        ProductTypeEnum productTypeEnum = getProductTypeEnum(getProjectType());
        if (productTypeEnum == null) return;
        
    	addUserLoanLimitRequestDTO.setProductTypeEnum(getProductTypeEnum(getProjectType())); //TODO: 

    	getUserForbidDubboService().addUserLibraLoanLimit(addUserLoanLimitRequestDTO);
	}
	
	private ProductTypeEnum getProductTypeEnum(ProjectTypeEnum projectTypeEnum) {
		switch (projectTypeEnum) {
		case SMALL_LOAN:
			return ProductTypeEnum.SMALL_LOAN;
		case SOCIAL_SECURITY_LOAN:
			return ProductTypeEnum.SOCIAL_SECURITY_LOAN;
		case CREDIT_CARD_LOAN:
			return ProductTypeEnum.CREDIT_CARD_LOAN_NEW;
		case CONSUME_LOAN:
			return ProductTypeEnum.CONSUME_LOAN;
		default:
			return null;
		}
	}

	/**
     * 用户信审模型(发送天秤)
     * @param
     */
    public void toRequestAutoAuditModel(String userId, Long projectId, Long flowId) {
    	// 判断该用户是首借还是复借
    	// 首借： 标准化信用卡首借用户信审模型（10101）
    	// 复借： 标准化信用卡复借用户信审模型（10102）
    	
    	// 步骤：
    	// 1. 流程状态判断
    	// 1. 构建模型
    	// 2. 异步调用天秤接口tripod服务
    	
    	// 判断流程状态
    	// shardingjdbc 强制走主库
		if (!HintManagerHolder.isMasterRouteOnly()) {
            HintManagerHolder.clear();
            HintManager hintManager = HintManager.getInstance();
            hintManager.setMasterRouteOnly();
        }
    	ProjectFlowExecuteRuntime projectFlowExecuteRuntime = projectFlowExecuteRuntimeMapperExt.selectByPrimaryKey(flowId);
		if (projectFlowExecuteRuntime == null) {
			log.error("借款流程数据异常,流程不存在,流程ID={}", flowId);
			return;
		}
		
//      LoanNodeTypeEnum nodeType = LoanNodeTypeEnum.enumof(projectFlowExecuteRuntime.getNodeId());
//		if (nodeType != LoanNodeTypeEnum.LOAN_SYSTEM_AUDIT) {
//			log.error("异常流程节点,流程ID={}", flowId);
//			return;
//		}
		
    	Project project = projectCommonService.queryProjectBasicInfo(projectId);
        if (project == null) {
            log.error("天称{}信审补漏,标的ID={},发生异常,原因是标的不存在.", getProductName(), projectId);
            // 清掉对应流程数据
            projectFlowExecuteService.failEndProjectFlowExecute(flowId, LoanNodeTypeEnum.LOAN_SYSTEM_AUDIT, "标的不存在");
        }
        
        if (!project.getStatus().equals(ProjectStatusEnum.CHECKING.getStatus())) {
            log.error("天称{}信审补漏,标的ID={},发生异常,原因是标的不在审核中状态.", getProductName(), projectId);
            return;
        }
        
        if (projectFlowExecuteRuntime.getRetryTimes() > 3) { //重试第四次时直接流标
			log.error("天秤{}信审重试3次做流标处理,流程ID={}", flowId);
			projectFlow(project.getProjectId(), flowId, LoanNodeTypeEnum.LOAN_SYSTEM_AUDIT, false, "重试3次调用天秤信审接口失败");
			return;
		}
    	
        //是否首借判断
    	isAgainLoan = loanAntiFraudLocalService.firstLoan(userId);
    	
    	log.info("额度评分通过之后,调用天秤{}信审,用户ID={},标的ID={}.", getProductName(), userId, projectId);
    	try {
    		AgainstFakeV2Response againstFakeV2Response = null;
    		CreditAduitFirstLoanRequest firstLoanReq = null;
    		CreditAduitAgainLoanRequest againLoanReq = null;
	    	if (isAgainLoan) {
	    		againLoanReq = creditCardAgainLoan(userId, project, String.valueOf(flowId));
	    		againstFakeV2Response = againLoan(againLoanReq);
	    	} else  {
	    		firstLoanReq = creditCardFirstLoan(userId, project, String.valueOf(flowId));
	    		againstFakeV2Response = firstLoan(firstLoanReq);
	    	}

			log.info("标的ID={},调用天秤信审接口,响应结果={}",project.getProjectId(),JSON.toJSONString(againstFakeV2Response));
	    	// 状态码 0:成功,1:请求参数错误,2:获取数据超时,3:数据异常,4:服务忙，稍后重试,5:其它错误
	    	// 如果不是成功或请求参数错误执行下面代码
	    	if (againstFakeV2Response.getCode() != AgainstFakeErrorCodeEnum.SUCCESS.getErrorCode()) {
				projectFlowExecuteService.updateProjectFlowExecuteRuntime(flowId,
						LoanNodeTypeEnum.LOAN_SYSTEM_AUDIT, ProjectFlowExecuteRuntimeNodeStatusEnum.EXCEPTION,
						"天秤信审服务异常");
			} else {
				//新增天秤请求记录
				addTianChengRequestRecord(userId, projectId, flowId,
						(isAgainLoan ? againLoanReq.getOrder_id() : firstLoanReq.getOrder_id()));
				//下一个流程节点：天秤信审回流
				projectFlowExecuteService.initNextStepProjectFlowExecute(flowId, LoanNodeTypeEnum.LOAN_SYSTEM_AUDIT, LoanNodeTypeEnum.LOAN_SYSTEM_AUDIT_BACK, null);
			}
	    	
	    	// 更新当前节点状态为执行中（不需要）
	    	//projectFlowExecuteService.updateProjectFlowExecuteRuntime(flowId, LoanNodeTypeEnum.LOAN_SYSTEM_AUDIT, ProjectFlowExecuteRuntimeNodeStatusEnum.HANDING, "");
    	} catch (Exception e) {
    		log.error("标的ID={},发生系统异常,错误信息={}", projectId, e);
    		// 更新当前节点状态为异常
    		projectFlowExecuteService.updateProjectFlowExecuteRuntime(flowId, LoanNodeTypeEnum.LOAN_SYSTEM_AUDIT, ProjectFlowExecuteRuntimeNodeStatusEnum.EXCEPTION, e.getMessage());
    	}
    }
    
    public void toGetTianchengCreditAuditResult(String userId, Long projectId, Long flowId) {
    	ProjectFlowExecuteRuntime projectFlowExecuteRuntime = projectFlowExecuteRuntimeMapperExt.selectByPrimaryKey(flowId);
		if (projectFlowExecuteRuntime == null) {
			log.error("借款流程数据异常,流程不存在,流程ID={}", flowId);
			return;
		}
		
    	Project project = projectCommonService.queryProjectBasicInfo(projectId);
        if (project == null) {
            log.error("天称{}信审补漏,标的ID={},发生异常,原因是标的不存在.", getProductName(), projectId);
            // 清掉对应流程数据
            projectFlowExecuteService.failEndProjectFlowExecute(flowId, LoanNodeTypeEnum.LOAN_SYSTEM_AUDIT, "标的不存在");
        }
    	
    	//1. 获取最新的order_id
        if (!HintManagerHolder.isMasterRouteOnly()) {
            HintManagerHolder.clear();
            HintManager hintManager = HintManager.getInstance();
            hintManager.setMasterRouteOnly();
        }
    	TianChengRequestRecord lastRecord = tianChengRequestRecordMapperExt.queryTcRequestRecord(flowId, getFunctionCode().getHeadFunctionCode());
    	String orderId = lastRecord.getOrderId();
    	
    	//2. 获取realName/idCard/mobile
    	TianchengCreditBaseInfoResponseDTO responseDto = getTianchengDataDubboService().getUserTianchengCreditBaseInfo(userId);
    	String realName = responseDto.getBaseInfo().getReal_name();
    	String idCard = responseDto.getBaseInfo().getIdentity_card();
    	String mob = responseDto.getBaseInfo().getMobile_phone();
    	
    	//3. 封装请求对象
    	KaDaiRepairServiceRequest request = new KaDaiRepairServiceRequest();
    	request.setOrder_id(orderId);
    	request.setIdentity_card(idCard);
    	request.setMobile_phone(mob);
    	request.setReal_name(realName);
    	
    	FailCloseFlowEvent failCloseFlowEvent = new FailCloseFlowEvent();
        failCloseFlowEvent.setToClose(false);
        failCloseFlowEvent.setToFlow(false);
    	
    	log.info("调用天秤补漏服务接口,用户ID={},标的ID={}.", userId, projectId);
    	JSONObject msgBodyJSON = null;
    	try {
    		AgainstFakeV2Response response = repair(request);
    		
    		if (response.getCode() != 0) {
//				projectFlowExecuteService.updateProjectFlowExecuteRuntime(flowId,
//						LoanNodeTypeEnum.LOAN_SYSTEM_AUDIT_BACK, ProjectFlowExecuteRuntimeNodeStatusEnum.EXCEPTION,
//						"天秤补漏服务异常");
				failCloseFlowEvent.setToFlow(true);
				failCloseFlowEvent.setErrorMsg("天秤补漏服务异常");
			} else {
				try{
		            msgBodyJSON = JSONObject.parseObject(response.getBody());
		        }catch (Exception ex){
		            log.error("5.1.5{}天秤补漏服务返回对象封装异常{}", getProductName(), ex);
//		            projectFlowExecuteService.updateProjectFlowExecuteRuntime(flowId,
//							LoanNodeTypeEnum.LOAN_SYSTEM_AUDIT_BACK, ProjectFlowExecuteRuntimeNodeStatusEnum.EXCEPTION,
//							"天秤补漏服务异常");
		            
		            failCloseFlowEvent.setToFlow(true);
					failCloseFlowEvent.setErrorMsg("天秤补漏服务异常");
		        }
			}
		} catch (Exception e) {
			log.info("调用天秤补漏服务接口异常,用户ID={},标的ID={},错误信息={}.", userId, projectId, e);
//			projectFlowExecuteService.updateProjectFlowExecuteRuntime(flowId,
//					LoanNodeTypeEnum.LOAN_SYSTEM_AUDIT_BACK, ProjectFlowExecuteRuntimeNodeStatusEnum.EXCEPTION,
//					"天秤补漏服务异常");
			
			failCloseFlowEvent.setToFlow(true);
			failCloseFlowEvent.setErrorMsg("天秤补漏服务异常");
		} finally {
			if (project == null) return;
			
			if (failCloseFlowEvent.getToFlow())
				projectFlow(project.getProjectId(), flowId, LoanNodeTypeEnum.LOAN_SYSTEM_AUDIT_BACK, false, failCloseFlowEvent.getErrorMsg());
		}
    	
    	//4. 解析结果并调用回调方法
    	CreditAuditBackRequestDTO creditAuditBackRequestDTO = new CreditAuditBackRequestDTO();
    	creditAuditBackRequestDTO.setDecision(msgBodyJSON.getInteger("decision"));
    	creditAuditBackRequestDTO.setProjectId(projectId);
    	creditAuditBackRequestDTO.setStatus(0);
    	creditAuditBackRequestDTO.setFlowId(flowId);
    	
    	creditAuditCallback(creditAuditBackRequestDTO);
    }
    
    /**
     * 流标
     * @param projectId
     * @param flowId
     * @param errorMsg
     */
    public void projectFlow(Long projectId, Long flowId, LoanNodeTypeEnum nodeType, boolean isNormalEnd, String errorMsg) {
    	// 1. 流标
		ProjectFlowRequestDTO requestDTO = new ProjectFlowRequestDTO();
	    requestDTO.setSubStatus(ProjectSubStatusEnum.MISCARRY_AUTO_FAILED);
	    requestDTO.setProjectId(projectId);
		projectDubboService.flow(requestDTO);
	    // 2. 通知用户流程 
	    loanLocalService.updateFinalAuditResult(projectId,FinalAuditResultEnum.NO_PASS);
	    // 3. 标签系统-审核模型流标事件，流标业务中已处理
	    // activityEventService.sendMsgForFlowProject(projectId, FlowProjectTypeEventEnum.AUDIT_MODEL_FLOW);
	    // 4. 终止流程（异常）
		if (isNormalEnd)
			projectFlowExecuteService.failEndProjectFlowExecute(flowId, nodeType, errorMsg);
		else 
			// 流程状态结束（成功）
            projectFlowExecuteService.successEndProjectFlowExecute(flowId, LoanNodeTypeEnum.PORTRAIT_AUTH);
    }
    
    public void updateProjectStatus(Long projectId, FinalAuditResultEnum finalAuditResultEnum){
        Project project2Update=new Project();
        project2Update.setProjectId(projectId);
        project2Update.setFinalAuditResult(finalAuditResultEnum.getResult());

        projectMapper.updateByPrimaryKeySelective(project2Update);
    }
    
    public CreditAduitFirstLoanRequest creditCardFirstLoan(String userId, Project project, String flowId) {
    	log.info("首借-获取天秤模型数据,用户ID={}.", userId);
    	CreditAduitFirstLoanRequest request = new CreditAduitFirstLoanRequest();
    	
		TianchengCreditBaseInfoResponseDTO responseDto = getTianchengDataDubboService().getUserTianchengCreditBaseInfo(userId);
		request.setBasic_info(TianchengModelParseService.parseBaseInfo(responseDto.getBaseInfo()));
		request.setWork_info(TianchengModelParseService.parseWorkInfo(responseDto.getWorkInfo()));
		request.setContact_person(TianchengModelParseService.parseContactPersonInfo(responseDto.getContacts()));
		
		request.setProject_id(String.valueOf(project.getProjectId()));
		request.setApply_amount(project.getContractAmount() == null ? 0 : project.getContractAmount().doubleValue());
		request.setNotify_url(TianchengModelParseService.buildNotifyUrl(webHttpUrl, TianchengCallbackEventEnum.SPEED_LOAN_AUDIT_POINT_FAKE, request.getProject_id(), getProjectType(), getFunctionCode()));
		
		Long orderId = snowflakeIdWorker.nextId();
		request.setOrder_id(String.valueOf(orderId));
		request.setTransDate(new Date());
		request.setTransNo(String.valueOf(orderId));
		request.setReserve(flowId);
		
		// 借用卡贷--增加驭信相关参数
		if (ProjectTypeEnum.CREDIT_CARD_LOAN.getValue().equals(project.getType())) {
			CreditScoreCardDTO creditScoreCardDTO = getTianchengDataDubboService().queryCreditScoreCardParam(userId, FunctionCodeEnum.LIBRA_CREDIT_CARD_LOAN_TWO.getHeadFunctionCode());
	        request.setYx_entry_id(creditScoreCardDTO.getYx_entry_id());
	        request.setYx_login_name(creditScoreCardDTO.getYx_login_name());	        	
		}
		
		return request;
		
    }
    
    /**
     * 构建
     * @param userId
     * @param projectId
     */
    public CreditAduitAgainLoanRequest creditCardAgainLoan(String userId, Project project, String flowId) {
    	log.info("复借-获取天秤模型数据,用户ID={}.", userId);
    	TianchengCreditBaseInfoResponseDTO responseDto = getTianchengDataDubboService().getUserTianchengCreditBaseInfo(userId);
    	
    	CreditAduitAgainLoanRequest request = new CreditAduitAgainLoanRequest();
    	request.setBasic_info(TianchengModelParseService.parseBaseInfo(responseDto.getBaseInfo()));
		request.setContact_person(TianchengModelParseService.parseContactPersonInfo(responseDto.getContacts()));
		request.setWork_info(TianchengModelParseService.parseWorkInfo(responseDto.getWorkInfo()));
		request.setProject_id(String.valueOf(project.getProjectId()));
		request.setApply_amount(project.getContractAmount() == null ? 0 : project.getContractAmount().doubleValue());
		request.setNotify_url(TianchengModelParseService.buildNotifyUrl(webHttpUrl, TianchengCallbackEventEnum.SPEED_LOAN_AUDIT_POINT_FAKE, request.getProject_id(), getProjectType(), getFunctionCode()));
		
		Long orderId = snowflakeIdWorker.nextId();
		request.setOrder_id(String.valueOf(orderId));
		request.setTransDate(new Date());
		request.setTransNo(String.valueOf(orderId));
		request.setReserve(flowId);
		
		// 借用卡贷--增加驭信相关参数
		if (ProjectTypeEnum.CREDIT_CARD_LOAN.getValue().equals(project.getType())) {
	        CreditScoreCardDTO creditScoreCardDTO = getTianchengDataDubboService().queryCreditScoreCardParam(userId, FunctionCodeEnum.LIBRA_CREDIT_CARD_LOAN_TWO.getHeadFunctionCode());
	        request.setYx_entry_id(creditScoreCardDTO.getYx_entry_id());
	        request.setYx_login_name(creditScoreCardDTO.getYx_login_name());	        	
		}
		
		return request;
    }
    
    /**
     * 增加天秤请求记录
     * @param
     */
    public void addTianChengRequestRecord(String userId, Long projectId, Long flowId, String orderId){
        TianChengRequestRecord record = new TianChengRequestRecord();
        record.setId(Long.valueOf(orderId));
        record.setFlowExecuteId(flowId);
        record.setFunctionCode(getFunctionCode().getHeadFunctionCode());
        record.setProjectId(projectId);
        record.setBorrowUserId(userId);
        record.setOrderId(orderId);
        record.setCreateTime(new Date());
        
        tianChengRequestRecordMapperExt.insertSelective(record);
    }
	
    /**
     * 首借调用天秤信审接口
     * @param request
     * @throws Exception 
     */
	public abstract AgainstFakeV2Response firstLoan(CreditAduitFirstLoanRequest request) throws Exception;
	
	/**
	 * 复借调用天秤信审接口
	 * @param request
	 * @throws Exception 
	 */
	public abstract AgainstFakeV2Response againLoan(CreditAduitAgainLoanRequest request) throws Exception;
	
	/**
	 * 复借调用天秤信审接口
	 * @param request
	 * @throws Exception 
	 */
	public abstract AgainstFakeV2Response repair(KaDaiRepairServiceRequest request) throws Exception;
	
	/**
	 * 获取当前产品名称
	 * @return
	 */
	public String getProductName() {
		return getProjectType().getDesc();
	}
	
	/**
	 * 获取当前产品类型
	 * @return
	 */
	public abstract ProjectTypeEnum getProjectType();
	
	/**
	 * 获取当前产品对应天秤FunctionCode
	 * @return
	 */
	public abstract FunctionCodeEnum getFunctionCode();
	
	public abstract TianchengDataDubboService getTianchengDataDubboService();
	
	public abstract UserForbidDubboService getUserForbidDubboService();
	
	@Setter
	@Getter
	public class FailCloseFlowEvent {
		private Boolean toClose;
		private String errorMsg;
		private Boolean toFlow;
	}
}
